﻿namespace WebPacker.Tests.Managers
{
	using System.Text;
	using NUnit.Framework;
	using WebPacker.Configuration;
	using WebPacker.Filters;
	using WebPacker.Helpers;
	using WebPacker.Packs;
	using WebPacker.Packs.Builders;
	using WebPacker.Packs.Resources;
	using WebPacker.Packs.Watchers;
	using WebPacker.Repositories;
	using WebPacker.VersionGenerators;

	[TestFixture]
	public class PackRepositoryTest
	{
		private const string Category = "repository";
		private readonly string cssPackMd5Version = "3702007c88f40ec9f9d3fdef71f0f951";

		private string testFile1 = TestHelper.GetSamplePath("test1.js", Category);
		private string testFile2 = TestHelper.GetSamplePath("test2.js", Category);
		private string testFile3 = TestHelper.GetSamplePath("style1.css", Category);

		[SetUp]
		public void PrepareSampleFiles()
		{
			TestHelper.PrepareSampleFiles(new string[] { "test1.js", "test2.js", "style1.css" }, Category);
		}

		[Test]
		public void GetResourcePackTest()
		{
			var repository = GetPackRepository();
			var resources = new string[] { testFile1, testFile2 };
			var ipack = repository.GetPack(PackType.JavaScript, resources);
			var pack = ipack as Pack;
			Assert.IsNotNull(pack);
			Assert.AreEqual(PackType.JavaScript, pack.PackType);
			Assert.IsNotNull(pack.VersionGenerator);
			Assert.IsInstanceOf<Md5VersionGenerator>(pack.VersionGenerator);

			var name = HashHelper.ComputeMd5HashString(((int)pack.PackType).ToString() + string.Join(string.Empty, resources));

			Assert.AreEqual(name, pack.Name);

			Assert.AreEqual("346ec21f5f8222ffdacf7523b608cc67", pack.Version);
			Assert.IsNotNull(pack.Resources);
			Assert.AreEqual(resources.Length, pack.Resources.Length);

			for (var i = 0; i < resources.Length; i++)
			{
				Assert.IsInstanceOf<FileResource>(pack.Resources[i]);
				Assert.AreEqual(resources[i], pack.Resources[i].Name);
			}
		}

		[Test]
		public void GetResourcePackSameTest()
		{
			var repository = GetPackRepository();
			var resources = new string[] { testFile1, testFile2 };
			var pack1 = repository.GetPack(PackType.JavaScript, resources);
			var pack2 = repository.GetPack(PackType.JavaScript, resources);
			Assert.IsNotNull(pack1);
			Assert.AreSame(pack1, pack2);
		}

		[Test, Sequential]
		public void GetPackErrorTest(
			[Values(PackType.JavaScript, PackType.Css, PackType.Css)]
			PackType packType,
			[Values("cssPack", "jsPack", "CSSPACK")]
			string packName)
		{
			var repository = GetPackRepository();
			Assert.Throws<WebPackerException>(() => repository.GetPack(PackType.JavaScript, "unknown"));
		}

		[Test]
		public void GetJavascriptPackTest()
		{
			var repository = GetPackRepository();
			var ipack = repository.GetPack(PackType.JavaScript, "jsPack");
			var pack = ipack as Pack;
			Assert.IsNotNull(pack);
			Assert.IsInstanceOf<YuiJavascriptMinifier>(pack.Filter);
			Assert.AreEqual("js", pack.Filter.Name);
			Assert.AreEqual("jsPack", pack.Name);
			Assert.AreEqual(PackType.JavaScript, pack.PackType);
			Assert.AreEqual("1.2.3", pack.Version);
			Assert.IsNotNull(pack.VersionGenerator);
			Assert.IsInstanceOf<ManualVersionGenerator>(pack.VersionGenerator);
			Assert.IsNotNull(pack.Resources);
			Assert.AreEqual(2, pack.Resources.Length);

			var res1 = pack.Resources[0];
			Assert.IsInstanceOf<FileResource>(res1);
			Assert.AreEqual(testFile1, res1.Name);
			Assert.AreEqual(Encoding.UTF8, ((FileResource)res1).Encoding);

			var res2 = pack.Resources[1];
			Assert.IsInstanceOf<FileResource>(res2);
			Assert.AreEqual(testFile2, res2.Name);
			Assert.AreEqual(Encoding.GetEncoding(1251), ((FileResource)res2).Encoding);
		}

		[Test]
		public void GetCssPackTest()
		{
			var repository = GetPackRepository();
			var ipack = repository.GetPack(PackType.Css, "cssPack");
			var pack = ipack as Pack;
			Assert.IsNotNull(pack);
			Assert.IsInstanceOf<YuiCssMinifier>(pack.Filter);
			Assert.AreEqual("css", pack.Filter.Name);
			Assert.AreEqual("cssPack", pack.Name);
			Assert.AreEqual(PackType.Css, pack.PackType);
			Assert.IsNotNull(pack.VersionGenerator);
			Assert.IsInstanceOf<Md5VersionGenerator>(pack.VersionGenerator);
			Assert.AreEqual(cssPackMd5Version, pack.Version);
			Assert.IsNotNull(pack.Resources);
			Assert.AreEqual(1, pack.Resources.Length);

			var res1 = pack.Resources[0];
			Assert.IsInstanceOf<FileResource>(res1);
			Assert.AreEqual(testFile3, res1.Name);
		}

		[Test, Sequential]
		public void GetSamePackTest(
			[Values(PackType.JavaScript, PackType.Css)]
			PackType packType,
			[Values("jsPack", "cssPack")]
			string packName)
		{
			var repository = GetPackRepository();
			var expected = repository.GetPack(packType, packName);
			var actual = repository.GetPack(packType, packName);
			Assert.AreSame(expected, actual);
		}

		private IPackRepository GetPackRepository()
		{
			var filters = new IFilter[]
			{
				new YuiCssMinifier { Name = "css" },
				new YuiJavascriptMinifier { Name = "js" }
			};

			var generators = new IVersionGenerator[]
			{
				new Md5VersionGenerator(),
				new ManualVersionGenerator()
			};

			var packInfos = new PackInfoCollection();
			packInfos.Monitoring = false;
			packInfos.VersionGeneratorName = "md5";

			packInfos.Add(new PackInfo
			{
				Name = "jsPack",
				BasePath = TestHelper.GetSampleFolder(Category),
				PackType = PackType.JavaScript,
				Monitoring = true,
				VersionGeneratorName = "manual",
				Version = "1.2.3",
				FilterName = "js",
				Resources = new ResourceInfo[]
				{ 
					new ResourceInfo("test1.js"),
					new ResourceInfo("test2.js") { Encoding = Encoding.GetEncoding(1251) }
				}
			});

			packInfos.Add(new PackInfo
			{
				Name = "cssPack",
				PackType = PackType.Css,
				FilterName = "css",
				Resources = new ResourceInfo[]
				{
					new ResourceInfo(testFile3)
				}
			});

			packInfos.Add(new PackInfo
			{
				Name = "cssPack2",
				PackType = PackType.Css,
				FilterName = "css",
				Monitoring = true,
				Resources = new ResourceInfo[]
				{
					new ResourceInfo(testFile3)
				}
			});

			var builder = new PackBuilder(filters, new CompositeWatcher(), generators);
			var repository = new PackRepository(builder);
			repository.SetPacks(packInfos);
			return repository;
		}
	}
}
